home *** CD-ROM | disk | FTP | other *** search
Wrap
/* * Copyright (c) 1990, 1991 Stanford University * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the name * Stanford may not be used in any advertising or publicity relating to * the software without the specific, prior written permission of * Stanford. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* $Header: /Source/Media/collab/TimeLine/RCS/select.c,v 1.0 91/09/30 17:02:47 chua Exp Locker: drapeau $ */ /* $Log: select.c,v $ * Revision 1.0 91/09/30 17:02:47 chua * Update to version 1.0 * * Revision 0.66 91/09/23 17:20:11 chua * In DrawSelectArea, set areaSelected to 0 initially. It will be set to 1 * if an area has been selected. * * Revision 0.65 91/09/19 17:29:07 chua * Make sure that variables are initialized properly. Change formatting slightly, * so that (if, for, while) statements with only one statement in them will not have * braces. * * Revision 0.64 91/09/16 15:13:33 chua * In calls to InstrumentNew, add an extra parameter at the end. (Refer to the comments * in instrument.c as to what this extra parameter represents). * * Revision 0.63 91/09/04 15:13:51 chua * Use AlertMessage whenever a notice_prompt is to be displayed. * * Revision 0.62 91/07/26 17:28:43 chua * In DrawSelectArea, update the start and end fields in the region info popup * window. * * Revision 0.61 91/07/17 10:38:20 chua * In the DrawSelectArea procedure, while drawing the rectangle, take into account * the actual time of the canvas starting position (tlFrame->canvasStart). * * The definition of the playback head position, lastX has been changed. It now * indicates its position in terms of pixel value at the lowest zoom level. So code * where lastX or the DrawPlaybackHead function is called will have some changes. * * Revision 0.60 91/07/09 18:25:07 chua * Made changes to the startX, endX variables so that they now store the position at the * largest zoom level (zoom level = 1). Thus, the appropriate multiplication or * division by the zoom level has to be made when these variables are used. This will * include lastX (position of the playback head) as well. * * Revision 0.59 91/07/09 17:03:16 chua * *** empty log message *** * * Revision 0.58 91/06/25 17:48:01 chua * Scale the positions of notes according to the zoom level, to cater for zooming. * * Revision 0.57 91/06/05 16:23:43 chua * Delete lines 245-250 in DeleteNotesFromList as we do not need to reset the * selectedInstrument pointer, since this will be done in the DeselectNote routine that * will be called by the InitNotesInfo function. * * Revision 0.56 91/06/04 17:37:27 chua * Added the copyright comments in the beginning of the file. * * Revision 0.55 91/06/04 17:31:15 chua * Replace all occurrences of clipInstHead with TimeLineWindow[0]->instHead, since * TimeLineWindow[0] is reserved for use as the clipboard. * * Revision 0.54 91/06/04 10:43:57 chua * Added a call to UpdateHeader to update the header of the frame whenever * there is a change in the status of the change flag. * * Revision 0.53 91/06/03 11:12:06 chua * Make changes to accomodate multiple documents. This involves identifying * which is the current active window, that is, the one where the last mouse * click was done. * * Revision 0.52 91/05/30 12:09:55 chua * Added an extra parameter (deselect) in the call to InitNotesInfo. * * Revision 0.51 91/05/29 14:45:04 chua * Remove the ClearNotesInfoList function calls as the InitNotesInfo procedure has been rewritten * such that the ClearNotesInfoList function is no longer required. * * Revision 0.50 91/05/24 16:37:58 chua * * * Revision 0.49 91/05/23 17:39:13 chua * *** empty log message *** * * Revision 0.48 91/05/22 16:42:34 chua * In the DeleteNotesFromList function (line 182), check for both areaSelected and noteSelected * instead of just areaSelected. * * Similar for lines 188 and line 319. * * Revision 0.47 91/05/22 14:00:53 chua * In the if-statements where if (... startX != endX) occurs, replace them with * if (... (areaSelected || noteSelected)). This is a way of checking if either a note or a * region is selected and eliminates errors found in the previous version. * * Revision 0.46 91/05/22 11:51:12 chua * If the PasteFromClipboard routine, 3rd line, instead of check if (areaSelected), check if * startX != endX, which indicates that either an area or a note has been selected. This * allows us to paste over a selected area or a selected note. * * Revision 0.45 91/05/17 16:58:58 chua * *** empty log message *** * * Revision 0.44 91/05/17 16:58:15 chua * *** empty log message *** * * Revision 0.43 91/05/17 16:57:24 chua * *** empty log message *** * * Revision 0.42 91/05/16 14:40:05 chua * In the DeleteNotesFromList function, a check is made to see if we are deleting from a region * or just a selected note. If it is the latter, we need to set the infoNote pointer for that * instrument to NULL, since the selected note is to be deleted, and the infoNote pointer will * point to nothing then. * * Revision 0.41 1991/05/15 02:48:51 chua * Added a new function CheckClipboardInstPresent, which is called within * the PasteFromClipboard function. * This function will go through the clipboard instrument list and make sure that all the * instruments on the clipboard are open and selected (if an area has been selected). * * An extra parameter is added to the DeleteNotesFromList function, refresh, which indicates * if a canvas refresh is necessary after deletion. The only time when it is not necessary * is if it is called from the PasteFromClipboard function, since a pasting operation will * follow the deletion and it is necessary only to refresh after the pasting has been done. * * In the PasteFromClipboard function, paste will now replace any selected area with the * contents of the clipboard (provided the selected area contains all the instruments in the * clipboard). Also, if the insertion point falls in the middle of a note, the pasting of * the clipboard contents for that instrument will occur only at the end of that note. * * Revision 0.40 1991/04/24 00:29:40 chua * This file contains the functions that handle the selection routines. The functions are: * DrawSelectArea - makes sure that the start points are less than the end points and highlights the * selected area on the screen. * CopyToClipboard - copies the selected area onto the clipboard, which is essentially another instrument * list resembling the TimeLine instrument list (described in instrument.c) * DeleteNotesFromList - deletes the selected notes from the TimeLine. * CreateDuplicateNoteList - Makes a duplicate note list from one that is in the clipboard. * PasteFromClipboard - Inserts what is contained in the clipboard onto the TimeLine document, placed at * where the playback head is. * */ static char selectrcsid[] = "$Header: /Source/Media/collab/TimeLine/RCS/select.c,v 1.0 91/09/30 17:02:47 chua Exp Locker: drapeau $"; #include "main.h" int clipDuration; /* * This function will first check the start and ending X and Y positions to make sure that the start is less than the end. * It then draws the shaded rectangle indicating the area selected. * Called by DrawCanvasEventHandler (canvas.c) */ void DrawSelectArea(tlFrame) TimeLineFramePtr tlFrame; { int temp; if (tlFrame->startX > tlFrame->endX) /* Make sure that startX is less than endX */ { temp = tlFrame->startX; tlFrame->startX = tlFrame->endX; tlFrame->endX = temp; } if (tlFrame->startY > tlFrame->endY) /* Make sure that startY is less than endY */ { temp = tlFrame->startY; tlFrame->startY = tlFrame->endY; tlFrame->endY = temp; } if (tlFrame->startX < 0) /* Make sure that startX is non-negative */ tlFrame->startX = 0; SetStartEndRegion (tlFrame, tlFrame->startX, tlFrame->endX); XFillRectangle(tlFrame->dpyDraw, tlFrame->xidDraw, tlFrame->gcLine, (tlFrame->startX / tlFrame->zoomLevel) - tlFrame->canvasStart, tlFrame->startY, (tlFrame->endX - tlFrame->startX) / tlFrame->zoomLevel, tlFrame->endY - tlFrame->startY); /* Fill the selected rectangle */ tlFrame->areaSelected = 0; if (tlFrame->startX != tlFrame->endX && tlFrame->startY != tlFrame->endY) /* Make sure that an area has really been selected */ { tlFrame->areaSelected = 1; tlFrame->noteSelected = 0; } } /* * This function checks the selected area and determines which notes belong in it and copies the selected area to the clipboard. * Partially selected notes are not included and are replaced by blank periods of time equivalent to the length of the partially selected portion * of the note. * We have to create new instrument and new note nodes for the clipboard, rather than simply setting pointers to the selected instrument and notes. * This is in case the original instruments are changed. The clipboard would not be affected by operations such as loading in a new file etc, * since it has its own allocated memory instead of just pointers. * Called by CutHandler and CopyHandler (edit.c) */ void CopyToClipboard(tlFrame) TimeLineFramePtr tlFrame; { int startApp, numApps; int i, finished; Instrument *origInst, *newInst; Note *newNote, *origNote; startApp = tlFrame->startY / (IconHeight + IconGap); /* Determine which instruments are selected */ numApps = tlFrame->endY / (IconHeight + IconGap) - startApp; if (numApps > 0 && (tlFrame->areaSelected || tlFrame->noteSelected)) /* Make sure that at least one instrument has been selected */ { FreeInstrumentList(TimeLineWindow[0]); /* Clear the old clipboard instrument list */ clipDuration = tlFrame->endX - tlFrame->startX; origInst = (Instrument *) FindInstrument(startApp, tlFrame); /* Get the first selected instrument */ TimeLineWindow[0]->numberOfApps = numApps; for (i=0; i < numApps; i++) { if (i == 0) /* Create new instruments for the clipboard */ { TimeLineWindow[0]->instHead = (Instrument *) InstrumentNew(0, origInst->port, TimeLineWindow[0], NULL); newInst = TimeLineWindow[0]->instHead; } else { newInst->next = (Instrument *) InstrumentNew(i, origInst->port, TimeLineWindow[0], NULL); newInst = newInst->next; } newInst->numnotes = 0; origNote = origInst->firstNote; finished = 0; while (origNote != NULL && !finished) /* Go through the notes list and copy those that are selected onto the clipboard */ { if (origNote->start > tlFrame->endX) /* Check if this note list is done */ finished = 1; else if (origNote->start >= tlFrame->startX && origNote->end <= tlFrame->endX) /* Copy the note into the clipboard instrument list */ { if (newInst->firstNote == NULL) { newInst->firstNote = (Note *) malloc(sizeof(Note)); newNote = newInst->firstNote; } else { newNote->next = (Note *) malloc(sizeof(Note)); newNote = newNote->next; } newInst->numnotes++; newNote->start = origNote->start - tlFrame->startX; newNote->end = origNote->end - tlFrame->startX; newNote->ms = origNote->ms; CalculateNoteTime(newNote); newNote->next = NULL; } origNote = origNote->next; } origInst = origInst->next; } } } /* * This function will delete the selected notes and/or time intervals from the instruments. * The parameter refresh indicates if the canvas is to be redrawn immediately after the notes are deleted. This may not be necessary if this function * is called from the paste routine, since we are going to paste notes right after the deletion and refreshing should only be done after the pasting. * The variables tempstartX and tempendX are used to keep track of the actual starting and end X positions of the region to be deleted. This is because * partially selected notes are not deleted. So if there are partially selected notes on both ends of the selected area, the area actually being deleted * would be less than the selected area. * Called by CutHandler and DeleteHandler (edit.c) */ void DeleteNotesFromList(refresh, tlFrame) int refresh; TimeLineFramePtr tlFrame; { int startApp, numApps; int i, finished; int tempstartX, tempendX; int numDeletedNotes; /* Keep track of number of notes deleted for an instrument */ Instrument *currentInst; Note *prevNote, *currentNote; startApp = tlFrame->startY / (IconHeight + IconGap); /* Determine which instruments are selected */ numApps = tlFrame->endY / (IconHeight + IconGap) - startApp; if (numApps > 0 && (tlFrame->areaSelected || tlFrame->noteSelected)) /* Make sure that at least one instrument has been selected */ { tlFrame->change = 1; /* Set the change flag on */ UpdateHeader(tlFrame, 1); currentInst = (Instrument *) FindInstrument(startApp, tlFrame); /* Find the first selected instrument in the selected area */ for (i=0; i < numApps; i++) { tempstartX = tlFrame->startX; tempendX = tlFrame->endX; numDeletedNotes = 0; currentNote = currentInst->firstNote; /* Go through the notes list to determine which note falls in the selected area */ prevNote = currentNote; finished = 0; while (currentNote != NULL && !finished) { if (currentNote->start < tlFrame->startX && currentNote->end >= tlFrame->startX) /* Overlapping note in the beginning of the selected region */ { tempstartX = currentNote->end; prevNote = currentNote; currentNote = currentNote->next; } else if (currentNote->start <= tlFrame->endX && currentNote->end > tlFrame->endX) { /* Overlapping note in the end of the selected region */ tempendX = currentNote->start; finished = 1; } else if (currentNote->start > tlFrame->endX) /* No need to go on anymore as further notes are out of the selected region */ finished = 1; else if (currentNote->start >= tlFrame->startX && currentNote->end <= tlFrame->endX) /* The whole note is in the selected region */ { if (currentNote == currentInst->firstNote) /* Check if the first note is to be deleted */ { currentInst->firstNote = currentNote->next; numDeletedNotes ++; free (prevNote); currentNote = currentInst->firstNote; prevNote = currentNote; } else { prevNote->next = currentNote->next; numDeletedNotes ++; free (currentNote); currentNote = prevNote->next; } } else { /* None of the above cases satisfied. Go on to check the next note on the list */ prevNote = currentNote; currentNote = currentNote->next; } } while (currentNote != NULL) /* Update the start and end positions of the notes following the selected region */ { /* Since an area has been deleted, the start and end points of the notes following */ currentNote->start -= (tempendX - tempstartX); /* the deleted area needs to be changed. */ currentNote->end -= (tempendX - tempstartX); CalculateNoteTime(currentNote); currentNote = currentNote->next; } currentInst->numnotes -= numDeletedNotes; currentInst->infoNote = NULL; InitNotesInfo(currentInst, 1, tlFrame); currentInst = currentInst->next; } tlFrame->noteSelected = 0; tlFrame->areaSelected = 0; SetStartEndRegion(tlFrame, 0, 0); if (refresh == 1) DrawCanvasRepaintHandler(tlFrame->TimeLine_window->DrawCanvas, tlFrame->paintWinDraw, tlFrame->dpyDraw, tlFrame->xidDraw, NULL); /* Redraw the canvas with the new changes */ } } /* * This function will take a clipboard note list and forms a duplicate copy of it for insertion onto the timeline. * Called by PasteFromClipboard (select.c) */ Note *CreateDuplicateNoteList(noteHeader, insertPoint) Note *noteHeader; long insertPoint; { Note *newNoteList, *origNote, *newNote; if (noteHeader == NULL) /* Take no action if the note list is empty */ return NULL; newNoteList = (Note *) malloc(sizeof(Note)); /* Create a new note list */ newNote = newNoteList; origNote = noteHeader; while (origNote != NULL) /* Go through the clipboard note list and duplicate the whole list */ { newNote->start = origNote->start + insertPoint; newNote->end = origNote->end + insertPoint; newNote->ms = origNote->ms; CalculateNoteTime(newNote); if (origNote->next != NULL) newNote->next = (Note *) malloc(sizeof(Note)); else newNote->next = NULL; newNote = newNote->next; origNote = origNote->next; } return (newNoteList); } /* * This function checks if each instrument in the clipboard is currently open on the timeline. If an area has been selected, the function * also checks to make sure that the instrument is selected. * If any of the instruments are not open or selected, a notice message notifying the user which instrument is not open/selected is displayed, * and an error message is returned to the calling function. * Called by PasteFromClipboard (select.c) */ int CheckClipboardInstPresent(tlFrame) TimeLineFramePtr tlFrame; { Instrument *clipInstrument, *instrument; char buf[70], buf1[70], buf2[70]; int found; clipInstrument = TimeLineWindow[0]->instHead; while (clipInstrument != NULL) { instrument = tlFrame->instHead; /* Find the corresponding instrument on the timeline */ found = 0; while (instrument != NULL && !found) { if (strcmp(instrument->port->appName, clipInstrument->port->appName) == 0) { if (tlFrame->areaSelected || tlFrame->noteSelected) /* If an area has been selected, check that the instrument is selected. */ { if (instrument->relativePosition >= tlFrame->startY / (IconHeight + IconGap) && instrument->relativePosition < tlFrame->endY / (IconHeight + IconGap)) found = 1; else /* If instrument is not in selected area, do not paste */ instrument = NULL; } else found = 1; } else instrument = instrument->next; } if (!found) /* At least one of the required applications is not open. */ { sprintf (buf, "Sorry, the application %s is not open or selected.", clipInstrument->port->appName); sprintf (buf1, "Pasting from the clipboard cannot be done unless all the"); sprintf (buf2, "applications in the clipboard are open and selected (if applicable)."); AlertMessage(tlFrame, buf, buf1, buf2); return (Error); } clipInstrument = clipInstrument->next; } return (OK); } /* * This function will paste the contents of the clipboard onto the current timeline document, starting from where the playback head is. * First, a check is made (by calling the function CheckClipboardInstPresent) to make sure that all the instruments in the clipboard are open * and are in the selected area (if an area has been selected). * If an area has been selected and the above check is ok, the notes in the selected area are deleted. However, no refreshing of the canvas is * done yet, since pasting is to be done next. The playback head will be redrawn to the starting position of the selected area. * If a playback head position is defined, the function will proceed to do the pasting operation. * It will find the matching instrument on the current timeline instrument list for each instrument in the clipboard instrument list. * It then goes through the timeline instrument notes list to determine where the insertion should be made. * Next, it will make a duplicate copy of the clipboard instrument notes list by calling the function CreateDuplicateNoteList (above). * The insertion of the duplicate clipboard instrument notes list is then made and the start and end positions of the original notes in the * timeline instrument notes list following the insertion point is updated. * The pop-up info window is then updated, and the changes displayed on the canvas by calling the Draw Canvas repaint handler. * * Note that if the insertion point falls in the middle of a note, the clipboard section for that instrument will only be pasted after the end of that * note. This may result in the pasted sections of different instruments starting at different insertion points. * * Called by PasteHandler (edit.c) */ void PasteFromClipboard(tlFrame) TimeLineFramePtr tlFrame; { Instrument *clipInstrument, *instrument; int found; long insertPoint; Note *prevNote, *currentNote, *nextNote, *newNoteList; if (CheckClipboardInstPresent(tlFrame) == OK) /* Check if all instruments in the clipboard are open or selected. */ { if (tlFrame->areaSelected || tlFrame->noteSelected) /* Check if either a note or an area is selected */ { DeleteNotesFromList(0, tlFrame); DrawPlaybackHead(tlFrame->startX, tlFrame); } } else return; /* No need to continue processing as at least one instrument is not open/selected */ if (tlFrame->lastX >= 0) /* Check that the playback head has been positioned somewhere on the timeline */ { clipInstrument = TimeLineWindow[0]->instHead; while (clipInstrument != NULL) { instrument = tlFrame->instHead; /* Find the corresponding instrument on the timeline */ found = 0; insertPoint = tlFrame->lastX; /* Set the initial insertion point to be where the playback head is */ while (instrument != NULL && !found) /* Now, an instrument is guaranteed to be found, since a check was made earlier */ { if (strcmp(instrument->port->appName, clipInstrument->port->appName) == 0) found = 1; else instrument = instrument->next; } if (instrument->firstNote == NULL) /* No notes currently in the instrument where the paste is to occur */ { newNoteList = CreateDuplicateNoteList(clipInstrument->firstNote, insertPoint); /* Get a duplicate copy of the clipboard instrument note list */ instrument->firstNote = newNoteList; } else { currentNote = instrument->firstNote; /* Go through the instrument note list to determine at which point in the */ prevNote = currentNote; /* note list should the paste occur. */ found = 0; while (currentNote != NULL && !found) { if (currentNote->start >= insertPoint) found = 1; else { prevNote = currentNote; currentNote = currentNote->next; } } if (currentNote == instrument->firstNote) /* Paste before all the notes in the current note list */ { nextNote = instrument->firstNote; newNoteList = CreateDuplicateNoteList(clipInstrument->firstNote, insertPoint); /* Get a duplicate copy of the clipboard instrument note list */ if (newNoteList != NULL) instrument->firstNote = newNoteList; } else { /* Set the previous note before the playback head to point to the */ if (prevNote->end > insertPoint) /* If the insert point falls in the middle of a note, insert after the note */ insertPoint = prevNote->end; newNoteList = CreateDuplicateNoteList(clipInstrument->firstNote, insertPoint); /* Get a duplicate copy of the clipboard instrument note list */ nextNote = prevNote->next; /* duplicated clipboard note list */ if (newNoteList != NULL) prevNote->next = newNoteList; } if (newNoteList != NULL) /* Set the end of the duplicated clipboard note list to point to the next */ { /* note after the playback head position */ currentNote = newNoteList; while (currentNote->next != NULL) currentNote = currentNote->next; currentNote->next = nextNote; } while (nextNote != NULL) /* Update the start and end positions of the notes following the selected region */ { nextNote->start += clipDuration; nextNote->end += clipDuration; CalculateNoteTime(nextNote); nextNote = nextNote->next; } } instrument->numnotes += clipInstrument->numnotes; InitNotesInfo(instrument, 1, tlFrame); /* Update the info pop-up window */ clipInstrument = clipInstrument->next; } tlFrame->change = 1; /* Set the change flag on */ UpdateHeader(tlFrame, 1); DrawCanvasRepaintHandler(tlFrame->TimeLine_window->DrawCanvas, tlFrame->paintWinDraw, tlFrame->dpyDraw, tlFrame->xidDraw, NULL); } }